package cn.by.wms.TypeHandler;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.SneakyThrows;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
    //对java基本类型的加强，可以包含更详细的数据类型，在泛型的使用者比较好。
    private JavaType javaType;
    //ObjectMapper是Jackson用于处理JSON数据。
    private static ObjectMapper objectMapper = new ObjectMapper();

    static {

        //JsonAutoDetect.Visibility.ANY 代表所有属性或字段都可以序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //以数组的方式存放到Redis，Class Type 全类名作为为第一个元素，Json字符串为第二个元素。
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);

    }

    public JsonTypeHandler(Class<T> type) {
        // 使用TypeFactory把我们java 的class 类型转成 jackson中的 类型
        //javaType 里面包含了类的详细信息，尤其是在泛型类处理的时候很有用。
        this.javaType = this.getJavaType(type);
    }

    public JsonTypeHandler(JavaType javaType) {
        this.javaType = javaType;
    }

    @Override
    @SneakyThrows
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        //把java对象转换为json字符串，使用的是objectMapper的方法
        ps.setString(i, objectMapper.writeValueAsString(parameter));

    }

    @Override
    @SneakyThrows
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {

        if(rs.getString(columnName) == null){
            return null;
        }
        //把json字符串转换为java对象，使用的是objectMapper的方法
        return (T) objectMapper.readValue(rs.getString(columnName), this.javaType);

    }

    private JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {

        return null;
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {

        return null;

    }
}